/**
 * @author 14544
 * @date 2020/3/27 17:06
 */

    // fetch() 方法是一种现代通用方法，那么我们就从它开始吧。它已经发展了几年了并在不断改进，现在它已经得到很多浏览器的支持了。
    // Fetch API 提供了一个获取资源的接口（包括跨域请求）。任何使用过 XMLHttpRequest 的人都能轻松上手，而且新的 API 提供了更强大和灵活的功能集。

let TEST_URL = '/gov/gov.do?methodname=queryDocStatuses&serviceid=gov_status';

// 最基础的fetch 用法
// Response 提供了多种基于 promise 的方法来获取不同格式的响应正文：
// response.json() —— 将 response 解析为 JSON 对象，
// response.text() —— 以文本形式返回 response，
// response.formData() —— 以 FormData 对象（form/multipart 编码（encoding），我们将在下一章中了解到更多）的形式返回 response。
// response.blob() —— 以 Blob （具有类型的二进制数据）形式返回 response，
// response.arrayBuffer() —— 以 ArrayBuffer （纯二进制数据）形式返回 response，
// 另外，response.body 是 ReadableStream 对象，它允许逐块读取正文，
/*{
    fetch(TEST_URL, {})
        .then(res => res.json())
        .then(data => {
            console.log(data)
        }).catch(err => console.error(err))
}*/

// 使用 await、async方法
/*{
   async function f() {
       let res = await fetch(TEST_URL,{})
       let data = await res.json()
       console.log(data)
   }
   f()
}*/

// headers response.headers 中有一个类似于 Map结构 的 headers 对象。
/*{
    async function f1() {
        let response = await fetch(TEST_URL, {});
        let headers = response.headers
        console.log(headers.entries().next())  // 使用 Iterator next api 手动遍历
        for (const [name, value] of headers) { // 遍历这个headers，可以获取所有的header，也可以单独获取 header.get('name')
            console.log(`${name}:${value}`)
        }
    }

    f1()
}*/

//创建一个 POST 请求，或者其他方法（HTTP method）的请求，我们需要使用 fetch 相关选项：
// method —— HTTP 方法（HTTP-method），例如 POST，
// body —— 其中之一：
// 字符串（例如 JSON），
// FormData 对象，以 form/multipart 形式发送数据，
// Blob/BufferSource 发送二进制数据，
// URLSearchParams，以 x-www-form-urlencoded 编码形式发送数据，很少使用。
/*
{
    fetch(TEST_URL, {
        method: 'POST',
        body: JSON.stringify({name: 'fetch'}),
        headers: {
            'Content-type': 'application/json;charset=utf-8'
            //请注意，如果 body 是字符串，Content-Type 默认会设置为 text/plain;charset=UTF-8。所以我们使用 headers 值为 application/json 来代替默认值，这是 JSON 编码的数据的正确格式。
        }
    }).then(res => res.json()).then(data => {console.log(data)})
}*/


// 创建能从一组 GitHub 用户数组获取一组数据的异步函数 getUsers(names)，从 GitHub 获取用户信息并返回一组 GitHub 用户信息的数组。
// 给定 USERNAME 的用户信息的 GitHub 网址是：https://api.github.com/users/USERNAME。

// 总要细节：
// 每一个用户都应该有一个 fetch 请求，并且请求是独立的不用彼此等待。因此数据能尽快获取到。
// 如果任意一个请求失败了，或者没有这个用户，函数应该返回 null 到最终结果数组中。
{
    async function getUsers(names) {
        let jobs = [];

        for (let name of names) {
            let job = new Promise((resolve, reject) => {
                fetch(`https://api.github.com/users/${name}`).then(
                    successResponse => {
                        if (successResponse.status !== 200) {
                            resolve(name+'  null'); // 不是200 这里把null resolve回去，而不是reject，因为这样结果数组才能获取到值，不然会直接catch到错误去
                        } else {
                            resolve(successResponse.json());
                        }
                    },
                    failResponse => {
                        resolve(name+' null');  // 请求失败但是这里把null resolve回去，而不是reject，因为这样结果数组才能获取到值
                    }
                );
            })

            // let job = fetch(`https://api.github.com/users/${name}`).then(
            //     successResponse => {
            //         if (successResponse.status !== 200) {
            //             return null;
            //         } else {
            //             return successResponse.json();
            //         }
            //     },
            //     failResponse => {
            //         return null;
            //     }
            // );

            jobs.push(job);
        }

        // Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时，成功和失败的返回值是不同的，
        // 成功的时候返回的是一个结果数组，而失败的时候则返回最先被reject失败状态的值。
        // 需要注意：每一个请求都会调用，只是失败时立刻返回最先被reject失败状态的值，而不是一个数组了，剩下的请求依然会调用，但是不再返回

        let results = await Promise.all(jobs); // 等待所有请求完毕 结果包含在一个数组里，每一个请求对应一个结果，这里结果的索引与jobs里请求的顺序一致

        console.log(results)

        return results;
    }

    let users = getUsers(['iliakan', 'no.such.users', 'remy']).then(res => console.log(res)).catch(err => console.log(err));

}

// Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的，
/*{
    let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('p1 执行...')
            resolve('p1 success')
        },1000)
    })

    let p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('p2 执行...')
            // resolve('p2 success')
            reject('p2 failed')
        }, 500)
    })
    let p3 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('p3 执行...')
            resolve('p3 success')
            // reject('p3 failed')
        }, 1500)
    })

    // 即便p1的结果获取的比p2要晚。但p1的索引还是在前面。这带来了一个绝大的好处：在前端开发请求数据的过程中，
    // 偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景，使用Promise.all毫无疑问可以解决这个问题。
    // 需要注意：每一个请求都会调用，只是失败时立刻返回最先被reject失败状态的值，而不是一个数组了，剩下的请求依然会执行
    Promise.all([p1, p3, p2]).then((result) => {
        console.log(result)
    }).catch((error) => {
        console.log(error)  // 打开的是 'failed'
    })
}*/

// Promse.race就是赛跑的意思，意思就是说，Promise.race([p1, p2, p3])里面哪个结果获得的快，就返回那个结果，不管结果本身是成功状态还是失败状态。
// 剩下的请求依然会执行，只是先返回最先成功或失败的那个请求
/*{
    let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('success')
        },1000)
    })

    let p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('failed')
        }, 500)
    })

    Promise.race([p1, p2]).then((result) => {
        console.log(result)
    }).catch((error) => {
        console.log(error)  // 打开的是 'failed'
    })
}*/
